<?php

namespace app\tool;

use MongoDB\Driver\BulkWrite;
use MongoDB\Driver\Command;
use MongoDB\Driver\Manager;
use MongoDB\Driver\Query;

class Mongo
{
    private $client;
    private $database;

    public function __construct($host,$port, $databaseName) {
        $this->client = new Manager("mongodb://{$host}:{$port}"); // 连接默认主机和端口为：mongodb://localhost:27017
        $this->database = $databaseName;
    }

    /**
     * 创建索引
     * @param $collectionName 集合名称
     * @param $field 索引字段
     * @param $sort 索引排序（1升序，-1降序）
     * @return \MongoDB\Driver\Cursor
     * @throws \MongoDB\Driver\Exception\Exception
     *
     * mongosh命令：db.collectionname.getIndexes();
     */
    public function createIndex($collectionName,$field,$sort){
        $database = $this->database;
        // 定义要执行的创建索引命令
        $cmd = new Command([
            'createIndexes' => $collectionName,
            'indexes' => [
                [
                    'key' => [$field => $sort], // 定义索引键，例如：字段1升序
                    'name' => 'indexName', // 索引名称
                    // 其他可选参数，例如：
                    // 'unique' => true, // 创建唯一索引
                    // 'sparse' => true, // 创建稀疏索引
                    // 'expireAfterSeconds' => 60, // 设置过期时间
                    // 'background' => true, // 后台创建索引
                    // 'partialFilterExpression' => ['field2' => ['$gte' => 10]], // 创建部分索引
                ]
            ]
        ]);

        // 执行命令并获取结果
        $result =$this->client->executeCommand($database, $cmd);
        return $result;
    }

    /**
     * 创建集合
     * @param $collectionName 集合名称
     * @return mixed
     */
    public function createCollection($collectionName){
        $database = $this->database;
        // 定义要执行的创建集合命令
        $cmd = new Command([
            'create' => $collectionName,
            // 你可以添加其他命令参数，例如：
            // 'capped' => true, // 创建固定大小的集合
            // 'size' => 64 * 1024, // 集合的最大大小（字节）
            // 'max' => 1000, // 集合的最大文档数（如果设置了 capped）
        ]);

        $result =$this->client->executeCommand($database, $cmd);
        return $result;
    }

    /**
     * 写入数据
     * @param $collectionName 集合名称
     * @param $documentArr 数据文档数组
     * @return \MongoDB\Driver\WriteResult
     *
     * mongosh命令：1、db.collectionname.insertOne();    //写入一个文档
     *             2、db.collectionname.insertMany([]); //写入多个文档
     */
    public function insert($collectionName,$documentArr) {
        $database = $this->database;

        //写入方案一
        $cmd = new Command([
            'insert' => "$collectionName", // 指定数据库和集合
            'documents' => $documentArr
        ]);

        $this->client->executeCommand($database, $cmd);


//        写入方案二
//        $bulk = new BulkWrite();
//        foreach($documentArr as $val){
//            $bulk->insert($val);
//        }
//
//        $result = $this->client->executeBulkWrite("{$database}.{$collectionName}",$bulk);
    }

    /**
     * @param $collectionName 集合名称
     * @param $query $eq(等于),$gt(大于),$lt(小于),$gte(大于等于),$lte(小于等于),$ne(不等于),$in(值在数组里),$nin(值不在)
     * @param $sort 排序
     * @return void
     */
    public function query($collectionName,$query = [],$sort=[],$limit=null) {
        $database = $this->database;
        $filter = [];
        $options = [];
        foreach ($query as $val){
            if(isset($val['filter'])){
                $filter[$val['key']] = [$val['filter']=>$val['value']];
            }else{
                $filter[$val['key']] = $val['value'];
            }
        }

        $options['projection'] = ['_id' => 0];
        if(!empty($sort)){
            $options['sort'] = [$sort['key'],$sort['value']];
        }
        if($limit){
            $options['limit'] = $limit;
        }

        // 查询数据
        $query = new Query($filter, $options);
        $cursor = $this->client->executeQuery("{$database}.{$collectionName}", $query);

        $resultArr = [];

        foreach ($cursor as $document) {
            $resultArr[] = $document;
        }

        return $resultArr;
    }

    /**
     * 更新数据
     * @param $collectionName 集合名称
     * @param $query 查询条件 $eq(等于),$gt(大于),$lt(小于),$gte(大于等于),$lte(小于等于),$in(值在数组里),$nin(值不在)
     * @param $updateArr 更新数据
     * @return \MongoDB\Driver\WriteResult
     */
    public function update($collectionName,$query = [],$updateArr=[]){
        $database = $this->database;

        //这表示操作将按顺序执行，每个操作必须成功完成才能继续执行下一个操作。如果设置为 false，则可以跳过失败的写操作并继续执行其他操作。.
        $bulk = new BulkWrite(['ordered' => true]);

        $filter = [];
        $update = [];
        foreach ($query as $val){
            if(isset($val['filter'])){
                $filter[$val['key']] = [$val['filter'],$val['value']];
            }else{
                $filter[$val['key']] = $val['value'];
            }
        }

        foreach ($updateArr as $value){
            $update[$value['key']] = $value['value'];
        }

        $bulk->update($filter, ['$set' => $update]);
        $result = $this->client->executeBulkWrite("{$database}.{$collectionName}", $bulk);

        return $result;
    }

    /**
     * 删除数据
     * @param $collectionName
     * @param $query
     * @return \MongoDB\Driver\WriteResult
     *
     * mongosh命令：1、.db.collectionname.deleteMany({}); //删除当前集合所有文档
     */
    public function delete($collectionName,$query = []){
        $database = $this->database;

        //这表示操作将按顺序执行，每个操作必须成功完成才能继续执行下一个操作。如果设置为 false，则可以跳过失败的写操作并继续执行其他操作。.
        $bulk = new BulkWrite(['ordered' => true]);
        $filter = [];
        foreach ($query as $val){
            if(isset($val['filter'])){
                $filter[$val['key']] = [$val['filter'],$val['value']];
            }else{
                $filter[$val['key']] = $val['value'];
            }
        }

        $bulk->delete($filter);
        $result = $this->client->executeBulkWrite("{$database}.{$collectionName}", $bulk);

        return $result;
    }
}